/**
 * Copyright 2010 Google Inc.
 *
 * Main javascript for trips pages.
 *
 */

goog.provide('fsl.trips');

goog.require('fsl.ui');

goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.fx.DragDrop');
goog.require('goog.fx.DragDropItem');
goog.require('goog.fx.DragDropGroup');
goog.require('goog.json');
goog.require('goog.net.XhrIo');
goog.require('goog.style');
goog.require('goog.ui.Button');
goog.require('goog.ui.FormPost');
goog.require('goog.ui.Ratings');
goog.require('goog.ui.Textarea');
goog.require('goog.ui.Zippy');
goog.require('goog.Uri');
goog.require('goog.Uri.QueryData');

goog.require('soy');

goog.global.CLOSURE_NO_DEPS = false;


/**
 * Custom drag drop item that drags the whole activity when one if its children
 * is dragged.
 */
function FullElementDragDropItem(element, opt_data) {
  goog.fx.DragDropItem.call(this, element, opt_data);
  this.element_ = element;
}
goog.inherits(FullElementDragDropItem, goog.fx.DragDropItem);

FullElementDragDropItem.prototype.getDraggableElement = function(target) {
  return this.element_;
};


fsl.trips.Controller = function(uri) {
  // The page this controller is responsible for.
  this.uri_ = new goog.Uri(window.location);

  // The particular itinerary this controller is handling.
  this.itineraryKey_ = uri.getParameterValue('key');

  // Track the venues in all trips.
  this.venues = {};

  // Map a venue (key is venue json object, not id) to a form element.
  this.venueControls_ = {};

  // Track an itinerary.
  this.itinerary_ = {
    'venues': []
  };

  // UI
  this.createMap();
  this.createDragDrop();
  this.createMetadataForm();
};

fsl.trips.Controller.prototype.createMap = function() {
  this.map_ = new google.maps.Map(document.getElementById('map'), {
    zoom: 11,
    center: new google.maps.LatLng(37.44, -122.14),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  });
  this.infoWindow_ = new google.maps.InfoWindow();
};

fsl.trips.Controller.prototype.createMetadataForm = function() {
  var itineraryMetadata = document.getElementById('itineraryMetadata');

  this.titleTextarea_ = new goog.ui.Textarea();
  this.titleTextarea_.decorate(document.getElementById('itineraryTitle'));

  this.descriptionTextarea_ = new goog.ui.Textarea();
  this.descriptionTextarea_.decorate(
      document.getElementById('itineraryDescription'));

  // Save
  this.saveButton_ = new goog.ui.Button('Save');
  var self = this;
  goog.events.listen(this.saveButton_,
      goog.ui.Component.EventType.ACTION,
      function(event) {

        // Update all venues based on their editor controls.
        for (var venueIndex in self.itinerary_.venues) {
          var venue = self.itinerary_.venues[venueIndex];
          var control = self.venueControls_[venue.id];

          venue.comment = control.comment.getValue();
          venue.rating = control.rating.getValue();
        }

        var jsonSerializer = new goog.json.Serializer();
        var post = new goog.ui.FormPost();
        var postParams = {
          'itinerary': jsonSerializer.serialize({
            'title': self.titleTextarea_.getValue(),
            'description': self.descriptionTextarea_.getValue(),
            'locality': 'Some Locality',
            'venues': self.itinerary_.venues
          })
        };
        if (self.itineraryKey_) {
          postParams['key'] = self.itineraryKey_;
        }
        post.post(postParams, '/itinerary');
      });
  this.saveButton_.render(itineraryMetadata);
};

fsl.trips.Controller.prototype.createDragDrop = function() {

  // Elements in "allTrips" (left column)
  this.allTripsList_ = document.getElementById('allTripsList');

  // Elements in "itinerary" (right column)
  var itineraryColumn = document.getElementById('itinerary');
  this.itineraryList_ = document.getElementById('itineraryList');

  // Make activities draggable /into/ the itinerary. (Target)
  this.itineraryDragTarget_ = new goog.fx.DragDrop(itineraryColumn);
  this.itineraryDragTarget_.setDragClass('opacity_40');
  this.itineraryDragTarget_.init();

  // Add a venue to the itinerary on drop.
  var self = this;
  goog.events.listen(this.itineraryDragTarget_, 'drop',
    function dragEnd(event) {
      var venue = event.dragSourceItem.getData();
      self.addNewVenueToItinerary(venue);
    }
  );

  // Make activities dragable from all trips. (Source)
  this.allTripsDragItems_ = new goog.fx.DragDropGroup();
  this.allTripsDragItems_.addTarget(this.itineraryDragTarget_);
  this.allTripsDragItems_.setDragClass('opacity_40');
  this.allTripsDragItems_.init();
}

fsl.trips.Controller.prototype.createMarker = function(venue) {
  var latLng = new google.maps.LatLng(venue.geolat, venue.geolong);
  var marker = new google.maps.Marker({
      map: this.map_,
      position: latLng,
      title: venue.name
  });
  var self = this;
  google.maps.event.addListener(marker, 'click',
    function click(event) {
        self.infoWindow_.setContent(
            soy.renderAsFragment(fsl.ui.tripsVenue, {venue: venue}));
        self.infoWindow_.open(self.map_, marker);
    }
  );
};

fsl.trips.Controller.prototype.updateItinerary = function(itinerary) {
  this.itinerary_ = itinerary;
  for (var venueIndex in this.itinerary_.venues) {
    var venue = this.itinerary_.venues[venueIndex];
    this.addExistingVenueToItinerary(venue);
  }
  this.titleTextarea_.setContent(this.itinerary_.title);
  this.descriptionTextarea_.setContent(this.itinerary_.description);
}

fsl.trips.Controller.prototype.addNewVenueToItinerary = function(venue) {
  this.itinerary_.venues.push(venue);
  this.addExistingVenueToItinerary(venue);
};

fsl.trips.Controller.prototype.addExistingVenueToItinerary = function(venue) {

  // Fragment for the venue
  var venueFragment = soy.renderAsFragment(fsl.ui.venueEdit, {venue: venue});
  var venueForm = goog.dom.getElementByClass('venue-edit-form', venueFragment);
  var venueRating = goog.dom.getElementByClass('venue-edit-rating', venueFragment);
  var venueRatingValue = goog.dom.getElementByClass('venue-edit-rating-value', venueFragment);
  var venueComment = goog.dom.getElementByClass('venue-edit-comment', venueFragment);

  // Add a ratings do-dad.
  var rating = new goog.ui.Ratings();
  if (venue.rating > 0) {
    rating.setSelectedIndex(venue.rating - 1);
  }
  rating.render(venueRating);

  // Add a text area do-dad.
  var commentTextarea = new goog.ui.Textarea();
  commentTextarea.decorate(venueComment);
  if (venue.comment) {
    commentTextarea.setValue(venue.comment);
  } else {
    goog.style.showElement(venueComment, false);
  }

  // Unhide the comment text area if clicked.
  var self = this;
  goog.events.listen(venueFragment, goog.events.EventType.CLICK, function(event) {
    goog.style.showElement(venueComment, true);
  });

  // Bond a venue to the controls that edit the venue.
  var control = {
    'name': venue.name,
    'comment': commentTextarea,
    'rating': rating
  };
  this.venueControls_[venue.id] = control;

  // List item for the fragment
  var venueLi = goog.dom.createDom('li', null, venueFragment);
  goog.dom.appendChild(this.itineraryList_, venueLi);
}

fsl.trips.Controller.prototype.itineraryXhr = function() {
  var queryData = new goog.Uri.QueryData();
  queryData.add('out', 'json');
  queryData.add('key', this.itineraryKey_);
  var path = 'itinerary?' + queryData.toString();

  // Send an xhr to get all trips.
  var self = this;
  goog.net.XhrIo.send(path, function(e) {
    var xhr = e.target;
    self.updateItinerary(xhr.getResponseJson());
  });
};

fsl.trips.Controller.prototype.allTripsXhr = function() {
  var queryData = new goog.Uri.QueryData();
  queryData.add('out', 'json');
  var path = 'trips?' + queryData.toString();

  // Send an xhr to get all trips.
  var self = this;

  goog.net.XhrIo.send(path, function(e) {
    var xhr = e.target;
    var allTrips = xhr.getResponseJson();
    // Generate an object-map of all venues.
    for (var locality in allTrips) {
      var trips = allTrips[locality];
      for (var tripIndex in trips) {
        var trip = trips[tripIndex];
        for (var activityIndex in trip.activities) {
          var activity = trip.activities[activityIndex];
          self.venues[activity.venue.id] = activity.venue;
        }
      }
    }

    // Markers
    for (var venueId in self.venues) {
      var venue = self.venues[venueId];
      self.createMarker(venue);
    };

    // Center
    if (venue != undefined) {
      self.map_.setCenter(new google.maps.LatLng(venue.geolat, venue.geolong));
    }

    // A list for all trips
    var sortedLocalities = Object.keys(allTrips);
    sortedLocalities.sort();
    for (var localityIndex = 0; localityIndex < sortedLocalities.length; localityIndex++) {
    var locality = sortedLocalities[localityIndex];

      // An item for each locality
      var localityLi = goog.dom.createDom('li', null, locality);
      goog.dom.appendChild(self.allTripsList_, localityLi);

      // A list for each locality
      var localityUl = goog.dom.createDom('ul', {'class': 'localityList'});
      goog.dom.appendChild(localityLi, localityUl);
      var trips = allTrips[locality];
      for (var tripIndex in trips) {
        var trip = trips[tripIndex];

        // An item for each trip
        var tripLi = goog.dom.createDom('li', null, trip.started);
        goog.dom.appendChild(localityUl, tripLi);

        // A list for each trip
        var tripUl = goog.dom.createDom('ul', {'class': 'tripList'});
        goog.dom.appendChild(tripLi, tripUl);
        for (var activityIndex in trip.activities) {
          var activity = trip.activities[activityIndex];

          // An item for each activity, draggable
          var activityLi = goog.dom.createDom('li');
          goog.dom.appendChild(tripUl, activityLi);
          var venue = self.venues[activity.venue.id];
          var activityDragItem = new FullElementDragDropItem(activityLi, venue);
          self.allTripsDragItems_.addDragDropItem(activityDragItem);

          // A fragment for each activity
          var activityFragment = soy.renderAsFragment(
              fsl.ui.tripsActivity, {activity: activity});
          goog.dom.appendChild(activityLi, activityFragment);
        }

        // Zippy up each trip.
        var zippy = new goog.ui.Zippy(tripLi, tripUl);
      }
    }
  });
};

fsl.trips.Controller.prototype.start = function() {
  // Always get a list of places.
  this.allTripsXhr();

  // Possibly load an itinerary.
  if (this.itineraryKey_) {
    this.itineraryXhr();
  }
};


/**
 * Entry point for /trips.
 */
fsl.trips.init = function() {
  var controller = new fsl.trips.Controller(new goog.Uri(window.location));
  controller.start();
};
goog.exportSymbol('fsl.trips.init', fsl.trips.init);
